package exception;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;


/**
 * zqSoft Automation
 * 
 * @File:MyExceptionHandler.java
 * @author ylnie
 *         实现自己的HandlerExceptionResolver，该解析器只是对其中的一些比较典型的异常进行了拦截，然后返回对应的错误码
 *         ，当然你也可以继承DefaultHandlerExceptionResolver类， 然后重写其中的一些异常处理方法来实现自己的异常处理。
 * @Notes: <一些特别的描述的信息>
 * @Revision History: <<2014-7-29上午10:16:15>>, <<ylnie>>, <<Create>>
 */
public class MyExceptionHandler implements HandlerExceptionResolver {

    /**
     * 重写springMVC提供的异常处理方法
     * resolveException的第4个参数表示对哪种类型的异常进行处理。因为Exception类是所有异常类的基类,
     * 所以如果想根据异常类型的不同来进行不同的处理的话
     * ,可以在resolveException方法里面根据不同的异常类型进行不同的处理，返回不同的异常视图
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @return
     */
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView view = new ModelAndView();
        String exMessage = "";
        String exType = "";
        String exCode = "";
        // 根据不同异常类型转向不同页面
        if (ex instanceof BusinessException) {
            exCode = "20001";
            exType = "error-business";
            exMessage = ex.getMessage();
        }
        else if (ex instanceof ParameterException) {
            exCode = "30001";
            exType = "error-parameter";
            exMessage = ex.getMessage();
        }
        else {
            Map<String, String> resultException = createCommonMessageByExcepiton(ex);
            exMessage = resultException.get("message");
            exCode = resultException.get("code");
            exType = "error";
        }
        view.addObject("ex", ex);
        view.addObject("exType", exType);
        view.addObject("exCode", exCode);
        view.addObject("exMessage", exMessage);
        view.setViewName("exception/businessException.jsp");
        return view;
    }


    /**
     * 根据原始异常信息，生成易于理解的出错信息
     * 
     * @param e
     * @return
     */
    private Map<String, String> createCommonMessageByExcepiton(Exception e) {
        Map<String, String> resultException = new HashMap<String, String>();
        String message = null;
        String code = null;
        if (e instanceof SQLSyntaxErrorException) {
            message = processSQLSyntaxErrorException(e);
            code = "10001";
        }
        else if (e instanceof SQLException) {
            message = processSQLException(e);
            code = "10002";
        }
        else if (e instanceof NullPointerException) {
            message = processNullPointerException(e);
            code = "10003";
        }
        else if (e instanceof ClassNotFoundException) {
            message = processClassNotFoundException(e);
            code = "10004";
        }
        else if (e instanceof FileNotFoundException) {
            message = processFileNotFoundException(e);
            code = "10005";
        }
        else if (e instanceof ClassCastException) {
            message = processClassCastException(e);
            code = "10006";
        }
        else if (e instanceof IOException) {
            message = processIOException(e);
            code = "10007";
        }
        else if (e instanceof ArrayIndexOutOfBoundsException) {
            message = "数组越界，当前的index为：" + e.getLocalizedMessage();
            code = "10008";

        }
        else if (e instanceof IndexOutOfBoundsException) {
            code = "10009";

        }
        else if (e instanceof NumberFormatException) {
            message = processNumberFormatException(e);
            code = "10010";
        }
        else {
            message = e.getLocalizedMessage();
            code = "10011";
        }
        resultException.put("code", code);
        resultException.put("message", message);
        return resultException;
    }


    /**
     * 处理IndexOutOfBoundsException
     */
    @SuppressWarnings("unused")
	private static String processIndexOutOfBoundsException(Exception e) {
        String message = e.getLocalizedMessage();
        if (message.startsWith("Index:")) {
            message = "index越界，当前的index为：" + message.substring(message.indexOf(":") + 1, message.indexOf(",")) + "容器的容量是："
                            + message.substring(message.lastIndexOf(":") + 1);
        }
        return message;
    }


    /**
     * 处理SQLSyntaxErrorException
     * 
     * @param e
     * @return
     */
    private String processSQLSyntaxErrorException(Exception e) {
        String errorMessage = e.getMessage();
        if (errorMessage.startsWith("You have an error")) {
            errorMessage += "sql有语法错误，在" + errorMessage.substring(errorMessage.indexOf("near") + 4);
        }
        else {
            errorMessage = e.getLocalizedMessage();
        }
        return errorMessage;
    }


    /**
     * 处理SQLException
     * 
     * @param e
     * @return
     */
    private String processSQLException(Exception e) {
        String errorMessage = e.getMessage();
        if (errorMessage.startsWith("You have an error")) {
            errorMessage += "sql有语法错误，在" + errorMessage.substring(errorMessage.indexOf("near") + 4);
        }
        else {
            errorMessage = e.getLocalizedMessage();
            if (errorMessage.contains("\n")) {
                errorMessage = errorMessage.replaceAll("\n", " ");

            }
        }
        return errorMessage;
    }


    /**
     * 处理 NullPointException
     * 
     * @param e
     */
    private String processNullPointerException(Exception e) {
        String message = "空指针异常：" + e.getMessage() + "\n";
        StackTraceElement[] arr = e.getStackTrace();
        // 缩短stackTrace
        for (int i = 0; i < (arr.length < 4 ? arr.length : 3); i++) {
            message += arr[i].getClassName() + "(" + arr[i].getMethodName() + ":" + arr[i].getLineNumber() + ")\n";
        }
        return message;
    }


    /**
     * 处理FileNotFoundException
     * 
     * @param e
     */
    private String processFileNotFoundException(Exception e) {
        return e.getLocalizedMessage() + "文件找不到！";
    }


    /**
     * 处理ClassCastException
     */
    private String processClassCastException(Exception e) {
        String message = e.getLocalizedMessage();
        String arr[] = message.split("cannot be cast to");
        message = arr[0] + "不能强转为：" + arr[1];
        StackTraceElement st = e.getStackTrace()[0];
        message += "\n " + st.getClassName() + "(" + st.getMethodName() + ":" + st.getLineNumber() + ")";
        return message;
    }


    /**
     * 处理ClassNotFoundException
     * 
     * @param e
     */
    private String processClassNotFoundException(Exception e) {
        return "缺少" + e.getLocalizedMessage() + "类，请查找是否存在相关jar或者class文件!";
    }


    /**
     * 处理NumberFormatException
     * 
     * @param args
     */
    private String processNumberFormatException(Exception e) {
        String message = e.getLocalizedMessage();
        if (message.startsWith("For input string:")) {
            message = "数字格式异常,输入的字符串为：" + message.replace("For input string:", "");
        }
        return message;
    }


    /**
     * 处理IOException
     * 
     * @param e
     */
    private static String processIOException(Exception e) {
        String message = e.getLocalizedMessage();
        if (message.startsWith("Read error")) {
            message = "文件读取失败！输入流可能已经关闭！";
        }
        else if (message.startsWith("Write error")) {
            message = "文件写入失败！输出流可能已经关闭！";
        }
        return message;
    }

}
